The Application Kit Table of Contents | The Application Kit Index |
Derived from: public BHandler
Declared in: be/app/Looper.h
Library: libbe.so
A BLooper object creates a "message loop" that receives messages that are sent or posted to the BLooper. The message loop runs in a separate thread that's spawned (and told to run) when the BLooper receives a Run() call. If you're creating your own BLooper, you can invoke Run() from within the constructor.
You tell the loop to stop by sending the BLooper a B_QUIT_REQUESTED message, which invokes the object's Quit() function. You can also call Quit() directly, but you have to Lock() the object first (BLooper locking is explained later). Quit() deletes the BLooper for you.
|
You can deliver messages to a BLooper's thread by...
As messages arrive, they're added to the BLooper's BMessageQueue object. The BLooper takes messages from the queue in the order that they arrived, and calls DispatchMessage() for each one. DispatchMessage() locks the BLooper and then hands the message to a BHandler object by invoking the handler's MessageReceived() function. But which BHandler does the BLooper hand the message to? Here's the path:
After the handler is finished (when its MessageReceived() returns), the BMessage is automatically deleted and the BLooper is unlocked.
Access to many BLooper functions (and some BHandler functions) is proteced by a lock. To invoke a lock-protected functions (or groups of functions), you must first call Lock(), and then call Unlock() when you're done. The lock is scoped to the calling thread: Lock()/Unlock() calls can be nested within the thread. Keep in mind that each Lock() must balanced by an Unlock().
The BLooper constructor automatically locks the object. It's unlocked when Run() is invoked. This means that the Run() function—and any other lock-protected functions that you call before you call Run()—must be called from the thread that constructed the BLooper.
Because they delete themselves when told to quit, BLoopers can't be allocated on the stack; you have to construct them with new.
|
Assigns the BLooper object a name and then locks it (by calling Lock()). priority is a value that describes the amount of CPU attention the message loop will receive once it starts running, and portCapacity is the number of messages the BLooper can hold in its "message port" (this is not the message queue, as explained below).
After you construct the BLooper, you have to tell it to Run(). Because the object is locked, Run() can only be called from the thread that constructed the object. It's legal to invoke Run() from within a subclass implementation of the constructor.
A set of priority values are defined in kernel/OS.h; from lowest to highest, they are:
B_LOW_PRIORITY | For threads running in the background that shouldn't interrupt other threads. |
B_NORMAL_PRIORITY | For all ordinary threads, including the main thread. |
B_DISPLAY_PRIORITY | For threads associated with objects in the user interface, including window threads. |
B_URGENT_DISPLAY_PRIORITY | For interface threads that deserve more attention than ordinary windows. |
B_REAL_TIME_DISPLAY_PRIORITY | For threads that animate the on-screen display. |
B_URGENT_PRIORITY | For threads performing time-critical computations. |
B_REAL_TIME_PRIORITY | For threads controlling real-time processes that need unfettered access to the CPUs. |
Messages that are sent to a BLooper first show up in a port (as the term is defined by the Kernel Kit), and then are moved to the BMessageQueue. The capacity of the BMessageQueue is virtually unlimited; the capacity of the port is not. Although messages are moved from the port to the queue as quickly as possible, the port can fill up. A full port will block subsequent message senders.
The default port capacity (100), should be sufficient for most apps, but you can fiddle with it through the portCapacity argument.
|
Frees the message queue and all pending messages and deletes the message loop. BHandlers that have been added to the BLooper are not deleted, but BMessageFilter objects added as common filters are
In general, you should never delete your BLooper objects: With the exception of the BApplication object, BLoopers are destroyed by the Quit() function.
|
class myClass : public BLooper, public OtherClass { ... };
is safe, while
class myClass : public OtherClass, public BLooper { ... };
is not.
|
Returns the BLooper object that spawned the specified thread, or NULL if the thread doesn't belong to a BLooper.
|
|
These functions manage the BLooper's list of BMessageFilters. Message filters are objects that screen in-coming messages. In the case of BLooper, each message is passed through all filters in the list before it's passed on to DispatchMessage(). The order of the filters in the list is determinate. See the BMessageFilter class for details on how message filters work.
AddCommonFilter() adds filter to the end of the filter list (creating a BList container if necessary).
RemoveCommonFilter() removes filter from the list, but doesn't free the filter. It returns true if successful, and false if it can't find the specified filter.
SetCommonFilterList() deletes the current filter list and its contents, and replaces it with filters. All elements in filters must be BMessageFilter pointers. The BLooper takes ownership of all objects in filters, as well as filters itself. If filters is NULL, the current list is deleted without a replacement.
CommonFilterList() returns a pointer to the current list. You can examine the list but you shouldn't modify or delete it.
|
AddHandler() adds handler to the BLooper's list of BHandler objects, and RemoveHandler() removes it. Only BHandlers that have been added to the list are eligible to respond to the messages the BLooper dispatches.
AddHandler() fails if the handler already belongs to a BLooper; a BHandler can belong to no more than one BLooper at a time. It can change its affiliation from time to time, but must be removed from one BLooper before it can be added to another. RemoveHandler() returns true if it succeeds in removing the BHandler from the BLooper, and false if not or if the handler doesn't belong to the BLooper in the first place.
AddHandler() also calls the handler's SetNextHandler() function to assign it the BLooper as its default next handler. RemoveHandler() calls the same function to set the handler's next handler to NULL.
HandlerAt() returns the BHandler object currently located at index in the BLooper's list of eligible handlers, or NULL if the index is out of range. Indices begin at 0 and there are no gaps in the list. CountHandlers() returns the number of objects currently in the list; the count should always be at least 1, since the list automatically includes the BLooper itself. IndexOf() returns the index of the specified handler, or B_ERROR if that object isn't in the list.
For any of these functions to work, the BLooper must be locked.
See also: BHandler::Looper(), BHandler::SetNextHandler(), PostMessage(), the BMessenger class
|
The message that a BLooper passes to its handler(s) is called the "current message." These functions access the current message; they're meaningless (they return NULL) when called from outside the message processing loop.
CurrentMessage() simply returns a pointer to the current message without affecting the BMessage object itself. This is particularly useful to functions that respond to system messages (such as MouseDown() and ScreenChanged()), but that aren't sent the full BMessage object that initiated the response.
DetachCurrentMessage() removes the current message from the message queue and passes ownership of it to the caller; deleting the message is the caller's responsibility. This is useful if you want to delay the response to the message without tying up the BLooper. But be careful—if the message sender is waiting for a synchronous reply, detaching the message and holding on to it will block the sender.
|
DispatchMessage() is the BLooper's central message-processing function. It's called automatically as messages arrive in the looper's queue, one invocation per message. You never invoke DispatchMessage() yourself.
The default implementation passes message to handler by invoking the latter's MessageReceived():
target->MessageReceived(message);
The only exception is where message.what is B_QUIT_REQUESTED and handler is the looper itself; in this case, the object invokes its own QuitRequested() function.
You can override this function to dispatch the messages that your own application defines or recognizes. All unhandled messages should be passed to the base class version, as demonstrated below:
void MyLooper::DispatchMessage(BMessage *msg, BHandler *target) { switch ( msg->what ) { case MY_MESSAGE1: ... break; case MY_MESSAGE2: ... break; default: baseClass::DispatchMessage(msg, target); break; } }
Also, note that you mustn't delete message; it's deleted for you..
The system locks the BLooper before calling DispatchMessage() and keeps it locked for the duration of the function.
|
Lock() locks the BLooper. Locks are held within the context of a thread; while a BLooper is locked, no other thread can invoke its most important functions (AddHandler(), DispatchMessage(), etc.)
If the looper is already locked (by some other thread), Lock() blocks until the looper is unlocked. To set a timeout for the block, use LockWithTimeout() instead. timeout is measured in microseconds; if it's 0, the function returns immediately (with or without the lock); if it's B_INFINITE_TIMEOUT, it blocks without limit.
Unlock() unlocks a locked looper. It can only be called by the thread that currently holds the lock.
Calls to Lock()/LockWithTimeout() and Unlock() can be nested, but locking and unlocking must always be balanced. A single Unlock() will not undo a series of Lock()'s.
RETURN CODES
Lock() returns true if it was able to lock the looper, or if it's already locked by the calling thread, and false otherwise.
LockWithTimeout() returns:
|
These functions may be useful while debugging a BLooper.
LockingThread() returns the thread that currently has the BLooper locked, or –1 if the BLooper isn't locked.
IsLocked() returns true if the calling thread currently has the BLooper locked (if it's the locking thread) and false if not (if some other thread is the locking thread or the BLooper isn't locked).
CountLocks() returns the number of times the locking thread has locked the BLooper—the number of Lock() (or LockWithTimeout()) calls that have not yet been balanced by matching Unlock() calls.
CountLockRequests() returns the number of threads currently trying to lock the BLooper. The count includes the thread that currently has the lock plus all threads currently waiting to acquire it.
Sem() returns the sem_id for the semaphore that the BLooper uses to implement the locking mechanism.
See also: Lock()
|
Simply calls the inherited function. For the current release, the BLooper implementation of this function does nothing of importance.
See also: BHandler::MessageReceived()
|
Returns the queue that holds messages delivered to the BLooper's thread. You rarely need to examine the message queue directly; it's made available so you can cheat fate by looking ahead.
See also: the BMessageQueue class
|
|
Places a message at the far end of the BLooper's message queue. The message will be processed by DispatchMessage() when it comes to the head of the queue.
The message can be a full BMessage object (message), or just a command constant (command). In the former case, the message is copied and the caller retains ownership of the argument, which can be deleted as soon as PostMessage() returns. In the latter case, a BMessage is created (and deleted) for you.
handler is the designated handler for the message, and must be part of this BLooper's handler chain. If handler is (literally) NULL, the designated handler is the BLooper's preferred handler at the time DispatchMessage() is called. In the versions of PostMessage() that don't have a handler argument, the designated handler is the BLooper object itself.
Replies to the message are delivered to replyHandler. If a replyHandler isn't specified, replies are sent to be_app_messenger.
|
RETURN CODES
. The message was successfully posted.
|
Shuts down the message loop (if it's running), and deletes the BLooper. The object must be locked.
When Quit() is called from the BLooper's thread, the message loop is immediately stopped and any messages in the message queue are deleted (without being processed). Note that, in this case, Quit() doesn't return since the calling thread is dead.
When called from another thread, Quit() waits until all messages currently in the queue have been handled before it kills the message loop. It returns after the BLooper has been deleted.
|
Hook function that's invoked when the BLooper receives a B_QUIT_REQUESTED message. You never invoke this function directly. Derived classes implement this function to return true if it's okay to quit this BLooper, and false if not. Note that this function does not actually quit the object—the code that handles the B_QUIT_REQUESTED message does that.
BLooper's default implementation of QuitRequested() always returns true.
|
Spawns the message loop thread and starts it running. Run() expects the BLooper to be locked (once only!) when it's called; it unlocks the object before it returns. Keep in mind that a BLooper is locked when it's constructed.
|
RETURN CODES
Positive values. The thread was successfully spawned and started; this is the thread_id for the thread.
|
These functions set and return the BLooper's preferred handler—the BHandler object that should handle messages not specifically targetted to another BHandler.
To designate the current preferred handler—whatever object that may be—as the target of a message, pass NULL for the target handler to PostMessage() or to the BMessenger constructor.
Posting or sending messages to the preferred handler can be useful. For example, in the Interface Kit, BWindow objects name the current focus view as the preferred handler. This makes it possible for other objects—such as BMenuItems and BButtons—to target messages to the BView that's currently in focus, without knowing what view that might be. For example, by posting its messages to the window's preferred handler, a Cut menu item can make sure that it always acts on whatever view contains the current selection. See the chapter on the Interface Kit for information on windows, views, and the role of the focus view.
By default, BLoopers don't have a preferred handler; until one is set, PreferredHandler() returns NULL. Note however, that messages targeted to the preferred handler are dispatched to the BLooper whenever the preferred handler is NULL. In other words, the BLooper acts as default preferred handler, even though the default is formally NULL.
See also: BControl::SetTarget() and BMenuItem::SetTarget() in the Interface Kit, PostMessage()
|
These functions identify the thread that runs the message loop and the team to which it belongs. Thread() returns B_ERROR if Run() hasn't yet been called to spawn the thread and begin the loop. Team() always returns the application's team_id.
|
The default capacity of the port that holds incoming messages before they're placed in the BLooper's BMessageQueue. The capacity is set in the BLooper constructor.
The Application Kit Table of Contents | The Application Kit Index |
Copyright © 2000 Be, Inc. All rights reserved..